﻿using Abp.Domain.Repositories;
using Abp.Domain.Services;
using Abp.ObjectMapping;
using Abp.Runtime.Caching;
using AVIS.OutBound.Contents.Cache;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace AVIS.OutBound.Contents
{
    public class ContentManager : DomainService, IContentManager
    {
        private readonly IRepository<Content> _contentRepository;
        private readonly IObjectMapper _objectMapper;
        private readonly ICacheManager _cacheManager;

        public ContentManager(IRepository<Content> contentRepository,
            IObjectMapper objectMapper,
            ICacheManager cacheManager)
        {
            _contentRepository = contentRepository;
            _objectMapper = objectMapper;
            _cacheManager = cacheManager;
        }

        /// <summary>
        /// 获取最新的特惠活动
        /// </summary>
        /// <returns></returns>
        public List<PromotionInfo> GetLasterPromotions()
        {
            var cacheItems = _cacheManager.GetContentCache().Get("LasterPromotions",
                k =>
                {
                    DateTime Now = Abp.Timing.Clock.Now;
                    var query = from c in _contentRepository.GetAll()
                                where c.CatalogId == OutBoundConsts.M_CMS_CATALOG_PROMOTIONINFO
                                    && c.Field31 == true && c.PublishDate <= Now
                                    && c.Field21 <= Now && c.Field22 >= Now
                                orderby c.PublishDate descending, c.ModifyDate descending
                                select new ContentCacheItem
                                {
                                    Id = c.Id,
                                    CatalogId = c.CatalogId.Value,
                                    Field1 = c.Field1,
                                    Field2 = c.Field2,
                                    Field16 = c.Field16,
                                    Field36 = c.Field36,
                                    Field37 = c.Field37,
                                };
                    return query.ToList();
                });
            return cacheItems.Select(c => new PromotionInfo().MapFrom(c)).ToList();
        }

        /// <summary>
        /// 获取指定ID的特惠详情
        /// </summary>
        /// <param name="Id">内容ID</param>
        /// <returns></returns>
        public PromotionInfo GetPromotion(int Id)
        {
            var cacheItems = _cacheManager.GetContentCache().Get(Id.ToString(),
               k =>
               {
                   DateTime Now = Abp.Timing.Clock.Now;
                   var query = from c in _contentRepository.GetAll()
                               where c.Id == Id
                                    && c.CatalogId == OutBoundConsts.M_CMS_CATALOG_PROMOTIONINFO
                                    && c.Field31 == true && c.PublishDate <= Now
                                    && c.Field21 <= Now && c.Field22 >= Now
                               select new ContentCacheItem
                               {
                                   Id = c.Id,
                                   CatalogId = c.CatalogId.Value,
                                   Field1 = c.Field1,
                                   Field2 = c.Field2,
                                   Field16 = c.Field16,
                                   Field36 = c.Field36,
                                   Field37 = c.Field37,
                                   Field46 = c.Field46,
                               };
                   return query.Take(1).ToList();
               });

            return cacheItems.Select(c => new PromotionInfo().MapFrom(c)).FirstOrDefault();
        }

        /// <summary>
        /// 获取首页banner
        /// </summary>
        /// <param name="count"></param>
        /// <returns></returns>
        public List<Banner> GetBanner()
        {
            var cacheItems = _cacheManager.GetContentCache().Get("IndexBanner", k =>
            {
                DateTime Now = Abp.Timing.Clock.Now;
                var query = from c in _contentRepository.GetAll()
                            where c.CatalogId == OutBoundConsts.M_CMS_CATALOG_BANNER
                                && c.Field31 == true && c.PublishDate <= Now
                                && c.Field21 <= Now && c.Field22 >= Now
                            orderby c.PublishDate descending, c.ModifyDate descending
                            select new ContentCacheItem
                            {
                                Id = c.Id,
                                CatalogId = c.CatalogId.Value,
                                Field2 = c.Field2,
                                Field36 = c.Field36,
                                Field51 = c.Field51,
                            };

                // 进行权重取值法
                var banners = query.ToList();
                return banners;

                // 触屏不需要随机数的算法。
                //var list = GetRandomList(banners, count);
                //return list;
            });
            return cacheItems.Select(c => new Banner().MapFrom(c)).ToList();

        }

        /// <summary>
        /// 获取指定装备类型的车辆信息
        /// </summary>
        /// <param name="Type"></param>
        /// <returns></returns>
        public Content GetContentEquipments(string Type)
        {
            var cacheItems = _cacheManager.GetContentCache().Get(Type, f =>
            {
                var query = from c in _contentRepository.GetAll()
                            where c.CatalogId == OutBoundConsts.M_CMS_CATALOG_EQUIPMENT
                                 && c.Field26.ToString() == Type
                            select new ContentCacheItem
                            {
                                Id = c.Id,
                                CatalogId = c.CatalogId.Value,
                                Field1 = c.Field1,
                                Field31 = c.Field31,
                            };
                return query.Take(1).ToList();
            });
            var ContentEquipments = _objectMapper.Map<Content>(cacheItems.FirstOrDefault());
            return ContentEquipments;
        }

        #region 私有方法
        /// <summary>
        /// 算法：
        /// 1.每个广告项权重+1命名为w，防止为0情况。
        /// 2.计算出总权重n。
        /// 3.每个广告项权重w加上从0到(n-1)的一个随机数（即总权重以内的随机数），得到新的权重排序值s。
        /// 4.根据得到新的权重排序值s进行排序，取前面s最大几个。
        /// </summary>
        /// <param name="list">原始列表</param>
        /// <param name="count">随机抽取条数</param>
        /// <returns></returns>
        private IList<ContentCacheItem> GetRandomList(IList<ContentCacheItem> list, int count)
        {
            if (list == null || list.Count < count || count <= 0)
            {
                return list;
            }

            //计算权重总和
            int totalWeights = 0;
            for (int i = 0; i < list.Count; i++)
            {
                totalWeights += list[i].Field26.Value + 1;  //权重+1，防止为0情况。
            }

            //随机赋值权重
            Random ran = new Random(GetRandomSeed());  //GetRandomSeed()随机种子，防止快速频繁调用导致随机一样的问题 
            List<KeyValuePair<int, int>> wlist = new List<KeyValuePair<int, int>>();    //第一个int为list下标索引、第一个int为权重排序值
            for (int i = 0; i < list.Count; i++)
            {
                int w = (list[i].Field26.Value + 1) + ran.Next(0, totalWeights);   // （权重+1） + 从0到（总权重-1）的随机数
                wlist.Add(new KeyValuePair<int, int>(i, w));
            }

            //排序
            wlist.Sort(delegate (KeyValuePair<int, int> kvp1, KeyValuePair<int, int> kvp2)
            {
                return kvp2.Value - kvp1.Value;
            });

            //根据实际情况取排在最前面的几个
            IList<ContentCacheItem> newList = new List<ContentCacheItem>();
            for (int i = 0; i < count; i++)
            {
                ContentCacheItem entiy = list[wlist[i].Key];
                newList.Add(entiy);
            }

            //随机法则
            return newList;
        }

        /// <summary>
        /// 随机种子值
        /// </summary>
        /// <returns></returns>
        private int GetRandomSeed()
        {
            byte[] bytes = new byte[4];
            System.Security.Cryptography.RNGCryptoServiceProvider rng = new System.Security.Cryptography.RNGCryptoServiceProvider();
            rng.GetBytes(bytes);
            return BitConverter.ToInt32(bytes, 0);
        }
        #endregion
    }
}
